using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Reflection;
using System.Threading;
using Utils.WebFramework;
using System.Web.UI;
using System.Web.Compilation;
using System.IO;
namespace Utils.WebFramework
{
    public class IndexHandlerFactory : IHttpHandlerFactory 
    {
        internal IHttpHandler noneHttpHandler = null;

        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
            context.Response.Redirect(Framework.GetFramework().IndexUrl, false);
            return noneHttpHandler;
        }

        public void ReleaseHandler(IHttpHandler handler)
        {

        }
    }

    public class HttpHandlerFactory : IHttpHandlerFactory 
    {
        internal PageHandlerFactory pageHandlerFactory = (PageHandlerFactory)Activator.CreateInstance(typeof(PageHandlerFactory),true);
        internal DefaultHttpHandler defaultHttpHandler = new DefaultHttpHandler();
        internal IHttpHandler       noneHttpHandler    = null;

        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
            HttpApplication application = context.ApplicationInstance;

            string execFilePath = context.Request.AppRelativeCurrentExecutionFilePath;

            string[] items = execFilePath.Split('/');

            string lastMark = items.Length > 0 ? items[items.Length - 1] : string.Empty;

            NameValues actionData = new NameValues();

            string controller = items.Length > 1 ? items[1].Trim() : string.Empty;
            string action     = items.Length > 2 ? items[2].Trim() : string.Empty;

            action = action.Substring(0,action.LastIndexOf('.'));

            Httper httper = new Httper(controller, action);

            httper.url      = context.Request.Url.OriginalString;
            httper.encoding = context.Request.ContentEncoding;
            
            foreach (string key in context.Request.QueryString.Keys)
            {
                if ( key != null && !key.StartsWith("__"))
                {
                    httper[key] = context.Request.QueryString[key].Trim();
                }
            }

            foreach (string key in context.Request.Form.Keys)
            {
                if (key != null && !key.StartsWith("__"))
                {
                    httper[key] = context.Request.Form[key].Trim();
                }
            }

            foreach (string key in context.Request.Cookies.Keys)
            {
                if (key != null && !key.StartsWith("__"))
                {
                    httper[key] = context.Request.Cookies[key].Value.Trim();
                }
            }

            Stream stream = context.Request.InputStream;
            if ( stream != null )
            {
                httper.inStream = stream;
            }

            HttpFileCollection files = context.Request.Files;
            foreach(string key in files.AllKeys)
            {
                httper[key] = files[key];
            }

            string browser = context.Request.Browser.Browser;
            if ( !string.IsNullOrEmpty(browser) )
            {
                httper.browser = browser + "_" + context.Request.Browser.MajorVersion;
            }

            httper.address = context.Request.UserHostAddress;

            try
            {
                return ProcessHttper(context, requestType, httper);
            }
            catch (Exception ex)
            {
                Framework.GetFramework().Error = ex;
                httper.controller = "Utils";
                httper.action     = "Error";

                return ProcessHttper(context, requestType, httper);
            }
        }

        public void ReleaseHandler(IHttpHandler handler)
        {
            
        }

        private IHttpHandler ProcessHttper(HttpContext context, string requestType, Httper httper)
        {
            object obj = Framework.GetFramework().GetController(httper.controller);
            if (obj == null)
            {
                return defaultHttpHandler;
            }

            HttpObject httpObject = new HttpObject();

            httpObject.application = context.Application;
            httpObject.server   = context.Server;
            httpObject.request  = context.Request;
            httpObject.response = context.Response;

            string language = GetUserlanguage(context);
            Resource resource = Framework.GetFramework().GetResource(language);

            ActionResult actionResult = (ActionResult)obj.GetType().InvokeMember(httper.action, BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.IgnoreCase, Type.DefaultBinder, obj, new object[] { httper, httpObject, resource });
            context.Items["__actionresult"] = actionResult;
            context.Items["__resource"] = resource;
            context.Items["__httper"] = httper;

            ViewResult viewResult = actionResult as ViewResult;
            if (viewResult != null)
            {
                if (string.IsNullOrEmpty(viewResult.view))
                {
                    viewResult.view = httper.action;
                }

                string viewPath     = viewResult.ExecViewPath(httper.controller);
                string physicalPath = context.Server.MapPath(viewPath);

                return pageHandlerFactory.GetHandler(context, requestType, viewPath, physicalPath);
            }

            HttpResult httpResult = actionResult as HttpResult;
            if (httpResult != null)
            {
                context.Response.ContentType     = httpResult.contentType;
                context.Response.ContentEncoding = httpResult.Encoding;
                
                foreach(string name in httpResult.headers)
                {
                    context.Response.AddHeader(name, (string)httpResult.headers[name]);
                }

                context.Response.BinaryWrite(httpResult.stream.ToArray());

                return noneHttpHandler;
            }

            ReDirectResult reDirectResult = actionResult as ReDirectResult;
            if (reDirectResult != null)
            {
                return ProcessHttper(context, requestType, reDirectResult.Httper);
            }

            ReDirectUrlResult reDirectUrlResult = actionResult as ReDirectUrlResult;
            if (reDirectUrlResult != null)
            {
                context.Response.Redirect(reDirectUrlResult.Url, false);
                return noneHttpHandler;
            }

            return defaultHttpHandler;
        }

        private string GetUserlanguage(HttpContext context)
        {
            string language = context.Request.QueryString["__language"];
            if (string.IsNullOrEmpty(language))
            {
                language = context.Request.Form["__language"];
            }

            if (string.IsNullOrEmpty(language))
            {
                string[] languages = context.Request.UserLanguages;
                if (languages != null && languages.Length > 0)
                {
                    language = languages[0];
                    int pos = language.IndexOf(";");
                    if (pos != -1)
                    {
                        language = language.Substring(0, pos);
                    }
                }
                else
                {
                    language = Framework.GetFramework().Language;
                }
            }

            language = language.Trim();

            HttpCookie httpCookie = context.Request.Cookies["__language"];
            if (httpCookie == null || string.IsNullOrEmpty(httpCookie.Value) || language != httpCookie.Value.ToLower())
            {
                httpCookie = new HttpCookie("__language");
                httpCookie.Value = language;
                httpCookie.Expires = DateTime.MaxValue;
                context.Response.AppendCookie(httpCookie);
            }

            return language;
        }
    }
}
